/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package tarea.MemoriaIntermedia;

import java.util.LinkedList;
import java.util.Queue;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.*; 

/**
 *
 * @author UNSAAC73
 */
public class GestorMemoriaIntermedia {
    
    //static final Logger logger = Logger.getLogger("Gestion de Buffer");
    /* Represenat a los bloques de la memoria intermedia*/
    private Pagina[] buffer;
    // Numero de paginas en total en el buffer
    private int numeroPaginas;
    // Posicion en el buffer de la ultima pagina colocada
    private int posicionUltimaPagina = -1;
    // Cola para el control de sustitucion basada en LRU
    private Queue colaLRU;
    
    /* crea un nuevo Gestor de memoria intermedia
     * @param numeroPaginas
     */
    
    public GestorMemoriaIntermedia(int numeroPaginas){
        this.numeroPaginas = numeroPaginas;
        // Crea el buffer con paginas vacias
        buffer = new Pagina[numeroPaginas];
        // Crea una cola FIFO
        colaLRU = new LinkedList<Integer>();
    }
    
    /* devuelve una pagina conociendo el numero de pagina
     * recuperarPaginaDelBuffer
     */
    public Pagina recuperarPaginaDelBuffer(int numeroPagina){
        // Verificar si la pagina esta en el buffer
        int posicion = posicionDePaginaEnBuffer(numeroPagina);
        if (posicion >= 0) // la paina esta en e buffer
        {
            // Marcar pagina o bloquecomo recientemente referenciado
            colaLRU.remove(numeroPagina);
            colaLRU.add(numeroPagina);
            // devolver la pagina del buffer al solicitante
            return buffer[posicion];
        }
        return null;
    }
    
    public Pagina ponerPaginaEnBuffer(Pagina pagina){
        // Si la pagina esta en el buffer
        if (estaPaginaEnBuffer(pagina)){
            // no descartar ninguna pagina o bloque
            return null;
            // Actualizar
            
        } // Si la pagina no esta en el buffer,  pero con espacio
        else if(!bufferLLeno()){
            // Asignar la nueva pagina al bloque o pagina libre
            posicionUltimaPagina++;
            buffer[posicionUltimaPagina] = pagina;
            // Actualizar la LRU
            colaLRU.remove(posicionUltimaPagina);
            colaLRU.add(posicionUltimaPagina);
            return null;            
        } // Si la pagina no esta en el buffer, pero sin espacio
        else{
            // recuperar la pagina a descartar
            // Identificar el ID pagina a descartar de la cola LRU y 
            // conociendo el ID  de pagina ubicar la posicion de la pagina en el buffer
            //int numeroPaginaDescartada = (Integer) colaLRU.remove();            
            //int posicion = posicionDePaginaEnBuffer(numeroPaginaDescartada);
            int posicion = RecuperaPaginaNoClavada();
            if (posicion != -1)
            {
                // Extraer la pagina a descartar del buffer
                Pagina paginaDescartada = buffer[posicion];

                // Actualizar la nueva pagina en a posicion de la pagina descartada
                buffer[posicion] = pagina;
                // hacer que el ID  de la nueva pagina sea el mas recientemente
                // referenciado
                colaLRU.add(pagina.getNumeroPagina());                

                return paginaDescartada;   
            }
            else {
                JOptionPane.showMessageDialog (null, "No se puede insertar por que todas las paginas son clavadas");
                return null;
            }                                 
        }
    }
    
    public int RecuperaPaginaNoClavada()
    {
        int numeroPaginaDescartada = (Integer) colaLRU.remove();          
        // Conociendo el ID  de pagina ubicar la posicion de la pagina en el buffer
        int posicion = posicionDePaginaEnBuffer(numeroPaginaDescartada);
        Pagina paginaDescartada = buffer[posicion];
        if(paginaDescartada.isClavado())
        {
            boolean PagEncontrada = false;
            int posicion2 = -1;
            while(!PagEncontrada && (colaLRU.size() != 0))
            {
                int numeroPaginaDescartada2 = (Integer) colaLRU.remove();                
                posicion2 = posicionDePaginaEnBuffer(numeroPaginaDescartada2);
                Pagina paginaDescartada2 = buffer[posicion2];
                if(!paginaDescartada2.isClavado())
                {
                    PagEncontrada = true;
                }
            }
            if (PagEncontrada){
                return posicion2;
            }
            else
                return -1;                
        }
        else
            return posicion;
    }
    
     public Pagina ponerPaginaEnBufferInfo(Pagina pagina, int Nropagina, String Informacion){
        // Actualizar
        int Pos = posicionDePaginaEnBuffer(Nropagina);
        if (Pos != -1)
        {
            Pagina PagRecuperada = buffer[Pos];
            PagRecuperada.datos = Informacion;
            buffer[Pos] = PagRecuperada; 
            return PagRecuperada;
        }
        else {
             // Si la pagina esta en el buffer
            if (estaPaginaEnBuffer(pagina)){
                // no descartar ninguna pagina o bloque
                return null;
                // Actualizar

            } // Si la pagina no esta en el buffer,  pero con espacio
            else if(!bufferLLeno()){
                // Asignar la nueva pagina al bloque o pagina libre
                posicionUltimaPagina++;
                buffer[posicionUltimaPagina] = pagina;
                // Actualizar la LRU
                colaLRU.remove(posicionUltimaPagina);
                colaLRU.add(posicionUltimaPagina);
                return null;            
            } // Si la pagina no esta en el buffer, pero sin espacio
            else{
                // recuperar la pagina a descartar
                // Identificar el ID pagina a descartar de la cola LRU y 
                // conociendo el ID  de pagina ubicar la posicion de la pagina en el buffer
                //int numeroPaginaDescartada = (Integer) colaLRU.remove();            
                //int posicion = posicionDePaginaEnBuffer(numeroPaginaDescartada);
                int posicion = RecuperaPaginaNoClavada();
                if (posicion != -1)  
                {
                    // Extraer la pagina a descartar del buffer
                    Pagina paginaDescartada = buffer[posicion];

                    // Actualizar la nueva pagina en a posicion de la pagina descartada
                    buffer[posicion] = pagina;
                    // hacer que el ID  de la nueva pagina sea el mas recientemente
                    // referenciado
                    colaLRU.add(pagina.getNumeroPagina());                

                    return paginaDescartada;   
                }
                else {
                JOptionPane.showMessageDialog (null, "No se puede insertar por que todas las paginas son clavadas");
                return null;
            }    
                                     
            }
        }      
    }
    
    private int posicionDePaginaEnBuffer(int numeroPagina){
        int posicion = -1;
        for(int i = 0; i < buffer.length; i++) {
            if((buffer[i] != null) && (numeroPagina == buffer[i].getNumeroPagina())){
                posicion = i;
                break;
            }
        }
        return posicion;
    }
    
    private boolean estaPaginaEnBuffer(Pagina pagina){
        return (posicionDePaginaEnBuffer(pagina.getNumeroPagina()) != -1);
    }
            
    private boolean bufferLLeno(){
        return numeroPaginas - 1 == posicionUltimaPagina;
    }
    
    @Override
    public String toString() {
        String resultado = "";
        for (int i = 0; i < buffer.length; i++) {
            resultado += "Pagina[" + i + "]: " + buffer[i] + "\n";
        }
        return resultado + "\n" + this.colaLRU;
    }

    /*public int SiguienteIndice(){
        return posicionUltimaPagina++;
    }*/
    
    public String MostrarCola() {
        return this.colaLRU.toString();
    }
    
    public String MostrarBuffer() {
        String resultado = "";
        for (int i = 0; i < buffer.length; i++) {
            resultado += "Pagina[" + i + "]: " + buffer[i] + "\n";
        }
        return resultado;// + "\n" + this.colaLRU;
    }
            
    
    public static void main(String[] args) {
        // Crear un gestor de memoria
        GestorMemoriaIntermedia gestorBuffer = new GestorMemoriaIntermedia(6);
        // Paginas del Disco
        System.out.println("Paginas del Disco: ");
        Pagina[] paginas = new Pagina[10];
        for (int i = 0; i < paginas.length; i++) {
            Pagina pagina = new Pagina(i, "p" + i);
            paginas[i] = pagina;
            System.out.println(pagina);
        }

        System.out.println("Contenido del Gestor: ");
        System.out.println(gestorBuffer);


        for (int i = 0; i < paginas.length; i++) {
            gestorBuffer.ponerPaginaEnBuffer(paginas[i]);
        }

        System.out.println("Contenido del Gestor despues de poner bloques: ");
        System.out.println(gestorBuffer);

        System.out.println("Poner una página al Buffer: ");
        Pagina paginaN = new Pagina(10,"p10");
        Pagina paginaE = gestorBuffer.ponerPaginaEnBuffer(paginaN);
        System.out.println(paginaE);
        System.out.println(gestorBuffer);
        
        
        
        System.out.println("Recuperar una Pagina del Buffer: ");
        Pagina pagina1 = gestorBuffer.recuperarPaginaDelBuffer(7);
        System.out.println(pagina1);
        System.out.println(gestorBuffer);

        System.out.println("Recuperar otra Pagina del Buffer: ");
        Pagina pagina2 = gestorBuffer.recuperarPaginaDelBuffer(1);
        System.out.println(pagina2);
        System.out.println(gestorBuffer);
    }
}
